#include "threadPool.h"
#include <unistd.h>

//向双链表中插入元素 头插法
#define LL_INSERT(item, list)do {   \
    item->prev = NULL;              \
    item->next = list;              \
    if(NULL != list)                \
    {                               \
        list->prev = item;          \
    }                               \
    list = item;                    \
} while (0);


//在双向链表中删除节点 
#define LL_REMOVE(item, list)do             \
{                                           \
    if(NULL != item->prev)                  \
    {                                       \
        item->prev->next = item->next;      \
    }                                       \
    if(NULL != item->next)                  \
    {                                       \
        item->next->prev = item->prev;      \
    }                                       \
    if(list == item)                        \
    {                                       \
        list = item->next;                  \
    }                                       \
    item->prev = item->next = NULL;         \
} while (0);


//任务队列的头插
int push_front(struct NTASK* task, nthreadpool_t* pool)
{
    LL_INSERT(task, pool->tasks);
    if(pool->task_size == 1)
    {
        pool->tasks_end = task;
    }

    return 1;
}

//任务队列的尾插
int push_back(struct NTASK* task, nthreadpool_t* pool)
{
    task->next = task->prev = NULL;
    if(pool->tasks == NULL)
    {
        pool->tasks = pool->tasks_end = task;
        return 1;
    }

    pool->tasks_end->next = task;
    task->prev = pool->tasks_end;
    pool->tasks_end = task;

    return 1; 
}

//任务队列头删
int pop_front(struct NTASK* task, nthreadpool_t* pool)
{
    LL_REMOVE(task, pool->tasks);
    if(pool->tasks == NULL)
    {
        pool->tasks_end = NULL;
    }
    return 1;
}





//线程入口函数
static void* threadd_callback(void* arg)
{
    struct NWORKER* worker = (struct NWORKER*)arg;

    while(1)
    {
        pthread_mutex_lock(&worker->pool->mtx);
        //如果当前没有任务
        while(worker->pool->tasks == NULL)
        {
            if(worker->pool->terminate && worker->pool->tasks == NULL) //如果要终止线程
            {
                break;
            }
            //条件变量阻塞 条件变量先解锁，再加锁
            pthread_cond_wait(&worker->pool->cond, &worker->pool->mtx);
        }
        
        if(worker->pool->terminate && worker->pool->tasks == NULL)//如果要终止线程
        {
            pthread_mutex_unlock(&worker->pool->mtx);
            // printf("thread free, id=%d\tfree:%d\n", worker->id, worker);
            // LL_REMOVE(worker, worker->pool->workers);
            // free(worker);
            // worker = NULL;
            break;
        }

        struct NTASK * task = worker->pool->tasks;
        if(task)
        {
            LL_REMOVE(task, worker->pool->tasks);
            --worker->pool->task_size;
        }

        pthread_mutex_unlock(&worker->pool->mtx);

        task->task_func(task);
    }
}


//创建线程池
int thread_pool_create(nthreadpool_t* pool, int nthread)
{
    if(NULL == pool) return -1;
    if(nthread < 1) nthread = 1;
    memset(pool, 0, sizeof(nthreadpool_t));

    //设置线程池为运行状态
    pool->terminate = 0;

    //初始化互斥量
    pthread_mutex_t blank_mtx = PTHREAD_MUTEX_INITIALIZER;
    memcpy(&pool->mtx, &blank_mtx, sizeof(pthread_mutex_t));

    //初始化条件变量
    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
    memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));

    //创建工作线程
    for(int i = 0; i < nthread; ++i)
    {
        struct NWORKER* worker = (struct NWORKER*)malloc(sizeof(struct NWORKER));
        if(NULL == worker)
        {
            perror("malloc NWORKER error");
            exit(-1);
        }
        memset(worker, 0, sizeof(struct NWORKER));
        worker->pool = pool;
        // worker->terminate = 0;

        int ret = pthread_create(&worker->id, NULL, threadd_callback, worker);
        // printf("create thread id = %d, malloc = %d\n", worker->id, worker);
        if(ret)
        {
            perror("pthread create error");
            free(worker);
            exit(1);
        }

        //将线程添加到线程池
        LL_INSERT(worker, pool->workers);
    }

    return 0;
}

//向链表头部添加任务
int thread_pool_push_front(nthreadpool_t* pool, struct NTASK* task)
{
    pthread_mutex_lock(&pool->mtx);

    //如果已经销毁线程池就不添加任务了
    if(!pool->terminate)
    {
        push_front(task, pool);
        ++pool->task_size;
        pthread_cond_signal(&pool->cond);
        
        pthread_mutex_unlock(&pool->mtx);
        return 0;
    }


    pthread_mutex_unlock(&pool->mtx);
    return -1;
}


//向链表尾部添加任务
int thread_pool_push_back(nthreadpool_t* pool, struct NTASK* task)
{
    pthread_mutex_lock(&pool->mtx);

    //如果已经销毁线程池就不添加任务了
    if(!pool->terminate)
    {
        push_back(task, pool);
        ++pool->task_size;
        pthread_cond_signal(&pool->cond);
        
        pthread_mutex_unlock(&pool->mtx);
        return 0;
    }


    pthread_mutex_unlock(&pool->mtx);
    return -1;
}


//销毁线程池
int thread_pool_destroy(nthreadpool_t* pool)
{

    pthread_mutex_lock(&pool->mtx);
    //让所有线程执行完任务之后退出
    pool->terminate = 1;
    //广播信号量
    pthread_cond_broadcast(&pool->cond);
    pthread_mutex_unlock(&pool->mtx);

    //等待线程执行完退出并且是否资源
    struct NWORKER* worker = pool->workers;
    struct NWORKER* temp_worker = NULL;
    while(worker)
    {
        temp_worker = worker;
        pthread_join(worker->id, NULL);
        worker = worker->next;  

        printf("free worker = %d\tid = %ld\n", temp_worker, temp_worker->id);
        free(temp_worker);
        temp_worker = NULL;
    }

    puts("所有线程全部退出");

    return 0;
}


//返回当前的任务数量
__uint32_t get_task_size(nthreadpool_t* pool)
{
    pthread_mutex_lock(&pool->mtx);
    int size = pool->task_size;
    pthread_mutex_unlock(&pool->mtx);

    return size;
}